<%@ Page Language="C#" %>
<%@ Import namespace="SubSonic.Utilities"%>
<%@ Import Namespace="SubSonic" %>
<%
	//The data we need
	string providerName = "#PROVIDER#";
	string tableName = "#TABLE#";
	TableSchema.Table tbl = DataService.GetSchema(tableName, providerName, TableType.Table);
	DataProvider provider = DataService.Providers[providerName];
	ICodeLanguage lang = new CSharpCodeLanguage();

	TableSchema.TableColumnCollection cols = tbl.Columns;
	string className = tbl.ClassName;
	string thisPK = tbl.PrimaryKey.PropertyName;
	string varPK = tbl.PrimaryKey.ArgumentName;
	string varPKType = Utility.GetVariableType(tbl.PrimaryKey.DataType, tbl.PrimaryKey.IsNullable, lang);
  bool showGenerationInfo = false;
  
%>

<% if(showGenerationInfo)
   { %>
 //Generated on <%=DateTime.Now.ToString() %> by <%=Environment.UserName %>
<% }  %>
namespace <%=provider.GeneratedNamespace %>
{
	/// <summary>
	/// Strongly-typed collection for the <%=className%> class.
	/// </summary>

	[Serializable]
	public partial class <%=className%>Collection : ActiveList[<]<%= className%>, <%=className%>Collection[>] 
	{	   
		public <%=className%>Collection() {}
	}

	/// <summary>
	/// This is an ActiveRecord class which wraps the <%=tableName%> table.
	/// </summary>
	[Serializable]
	public partial class <%=className%> : ActiveRecord[<]<%= className%>[>]
	{
		#region .ctors and Default Settings
		
		public <%=className %>()
		{
		  SetSQLProps();
		  InitSetDefaults();
		  MarkNew();
		}
		
		private void InitSetDefaults() { SetDefaults(); }
		
		public <%=className %>(bool useDatabaseDefaults)
		{
			SetSQLProps();
			if(useDatabaseDefaults)
				ForceDefaults();
			MarkNew();
		}

		public <%=className %>(object keyID)
		{
			SetSQLProps();
			InitSetDefaults();
			LoadByKey(keyID);
		}
		 
		public <%=className %>(string columnName, object columnValue)
		{
			SetSQLProps();
			InitSetDefaults();
			LoadByParam(columnName,columnValue);
		}
		
		protected static void SetSQLProps() { GetTableSchema(); }
		
		#endregion
		
		#region Schema and Query Accessor
		public static Query CreateQuery() { return new Query(Schema); }
		
		public static TableSchema.Table Schema
		{
			get
			{
				if (BaseSchema == null)
					SetSQLProps();
				return BaseSchema;
			}
		}
		
		private static void GetTableSchema() 
		{
			if(!IsSchemaInitialized)
			{
				//Schema declaration
				TableSchema.Table schema = new TableSchema.Table("<%=tableName%>", TableType.Table, DataService.GetInstance("<%=providerName%>"));
				schema.Columns = new TableSchema.TableColumnCollection();
				schema.SchemaName = @"<%=tbl.SchemaName%>";
				//columns
				<%
				foreach(TableSchema.TableColumn col in cols)
				{
					string varName = "col" + col.ArgumentName;
				%>
				TableSchema.TableColumn <%=varName %> = new TableSchema.TableColumn(schema);
				<%=varName %>.ColumnName = "<%=col.ColumnName%>";
				<%=varName %>.DataType = DbType.<%=col.DataType %>;
				<%=varName %>.MaxLength = <%=col.MaxLength %>;
				<%=varName %>.AutoIncrement = <%=col.AutoIncrement.ToString().ToLower() %>;
				<%=varName %>.IsNullable = <%=col.IsNullable.ToString().ToLower()%>;
				<%=varName %>.IsPrimaryKey = <%=col.IsPrimaryKey.ToString().ToLower()%>;
				<%=varName %>.IsForeignKey = <%=col.IsForeignKey.ToString().ToLower()%>;
				<%=varName %>.IsReadOnly = <%= col.IsReadOnly.ToString().ToLower() %>;
				<% if (!String.IsNullOrEmpty(col.DefaultSetting))					   
				%>
						<%=varName%>.DefaultSetting = @"<%= col.DefaultSetting%>";
				<%
				if(col.IsForeignKey) %>
					<%=varName %>.ForeignKeyTableName = "<%= col.ForeignKeyTableName %>";
				schema.Columns.Add(<%=varName%>);
				<%
				}
				%>
				BaseSchema = schema;

				//add this schema to the provider
				//so we can query it later
				DataService.Providers["<%=providerName %>"].AddSchema("<%=tableName%>",schema);
			}
		}
		#endregion
		
		#region Props
		
		<%
			bool useNullables = tbl.Provider.GenerateNullableProperties;
			foreach(TableSchema.TableColumn col in cols)
			{
				string propName = col.PropertyName;
				string varType = Utility.GetVariableType(col.DataType, false, lang);
				string nullableVarType = Utility.GetVariableType(col.DataType, col.IsNullable, lang);

				if (useNullables || Utility.IsMatch(varType, nullableVarType))
				{
		%>  
		[XmlAttribute("<%=propName%>")]
		public <%=nullableVarType%> <%=propName%> 
		{
			get { return GetColumnValue[<]<%=nullableVarType%>[>]("<%=col.ColumnName%>"); }
			set { SetColumnValue("<%=col.ColumnName%>", value); }
		}
		<%
				}
			else
			{  
		%>
		
		//private <%= nullableVarType%> prop<%=propName%>;

		[XmlAttribute("<%=propName%>")]
		public <%= varType %> <%=propName%> 
		{
			get
			{
			<%= nullableVarType%> prop<%=propName%> = GetColumnValue[<]<%=nullableVarType%>[>]("<%=col.ColumnName%>");
				if (!prop<%=propName%>.HasValue)
					return <%= Utility.GetDefaultValue(col, lang)%>;
				return prop<%=propName%>.Value;
			}
		   set { SetColumnValue("<%=col.ColumnName%>", value); }
		}
		
		[XmlIgnore]
		public bool <%=propName%>HasValue
		{

			get { return GetColumnValue[<]<%=nullableVarType%>[>]("<%=col.ColumnName%>") != null; }
			set
			{
				<%= nullableVarType%> prop<%=propName%> = GetColumnValue[<]<%=nullableVarType%>[>]("<%=col.ColumnName%>");
				if (!value)
					SetColumnValue("<%=col.ColumnName%>", null);
				else if (value && !prop<%=propName%>.HasValue)
					SetColumnValue("<%=col.ColumnName%>", <%= Utility.GetDefaultValue(col, lang)%>);
		   }
		}
		
		<% 
			}
		}
		%>
		#endregion
		
		<%if (tbl.PrimaryKeyTables.Count > 0)
{%>
		#region PrimaryKey Methods
		<%
	TableSchema.PrimaryKeyTableCollection pkTables = tbl.PrimaryKeyTables;
	if (pkTables != null)
	{
		ArrayList usedMethodNames = new ArrayList();
		foreach (TableSchema.PrimaryKeyTable pk in pkTables)
		{
			TableSchema.Table pkTbl = DataService.GetSchema(pk.TableName, providerName, TableType.Table);
			if (pkTbl.PrimaryKey != null && CodeService.ShouldGenerate(pkTbl))
			{
				string pkClass = pk.ClassName;
				string pkClassQualified = provider.GeneratedNamespace + "." + pkClass;
				string pkMethod = pk.ClassNamePlural;
				string pkColumn = pkTbl.GetColumn(pk.ColumnName).PropertyName;
				
				if (Utility.IsMatch(pkClass, pkMethod))
				{
					pkMethod += "Records";
				}

				if (pk.ClassName == className)
				{
					pkMethod = "Child" + pkMethod;
				}

				if (usedMethodNames.Contains(pkMethod))
				{
					pkMethod += "From" + className;
					if (usedMethodNames.Contains(pkMethod))
					{
						pkMethod += pkColumn;
					}
				}

				usedMethodNames.Add(pkMethod);
				
				if(!String.IsNullOrEmpty(provider.RelatedTableLoadPrefix))
				{
					pkMethod = provider.RelatedTableLoadPrefix + pkMethod;
				}

				bool methodsNoLazyLoad = !provider.GenerateRelatedTablesAsProperties && !provider.GenerateLazyLoads;
				bool methodsLazyLoad = !provider.GenerateRelatedTablesAsProperties && provider.GenerateLazyLoads;
				bool propertiesNoLazyLoad = provider.GenerateRelatedTablesAsProperties && !provider.GenerateLazyLoads;
				bool propertiesLazyLoad = provider.GenerateRelatedTablesAsProperties && provider.GenerateLazyLoads;

				if (methodsNoLazyLoad)
				{
%>
		public <%= pkClassQualified %>Collection <%=pkMethod%>()
		{
			return new <%=pkClassQualified%>Collection().Where(<%=pkTbl.ClassName%>.Columns.<%=pkColumn%>, <%=tbl.PrimaryKey.PropertyName%>).Load();
		}
<%
			}
			else if (methodsLazyLoad)
			{
%>
		private <%= pkClassQualified %>Collection col<%=pkMethod%>;
		public <%= pkClassQualified %>Collection <%=pkMethod%>()
		{
			if(col<%=pkMethod%> == null)
				col<%=pkMethod%> = new <%= pkClassQualified %>Collection().Where(<%=pkTbl.ClassName%>.Columns.<%=pkColumn%>, <%=tbl.PrimaryKey.PropertyName%>).Load();
			return col<%=pkMethod%>;
		}
<%
			}
			else if (propertiesNoLazyLoad)
			{
%>
		public <%= pkClassQualified %>Collection <%=pkMethod%>
		{
			get { return new <%= pkClassQualified %>Collection().Where(<%=pkTbl.ClassName%>.Columns.<%=pkColumn%>, <%=tbl.PrimaryKey.PropertyName%>).Load(); }
		}
<%
			}
			else if (propertiesLazyLoad)
			{
%>		
		private <%= pkClassQualified %>Collection col<%=pkMethod%>;
		public <%= pkClassQualified %>Collection <%=pkMethod%>
		{
			get
			{
				if(col<%=pkMethod%> == null)
					col<%=pkMethod%> = new <%= pkClassQualified %>Collection().Where(<%=pkTbl.ClassName%>.Columns.<%=pkColumn%>, <%=tbl.PrimaryKey.PropertyName%>).Load();
				return col<%=pkMethod%>;			
			}
			set { col<%=pkMethod%> = value; }
		}
		<%
			}
		}
	}
}
%>
		#endregion
		<%   
	}
%>
			
		<%if (tbl.ForeignKeys.Count > 0) { %>
		#region ForeignKey Properties
		<%
			TableSchema.ForeignKeyTableCollection fkTables = tbl.ForeignKeys;

			if (fkTables != null)
			{
				ArrayList usedPropertyNames = new ArrayList();
				foreach (TableSchema.ForeignKeyTable fk in fkTables)
				{
					TableSchema.Table fkTbl = DataService.GetSchema(fk.TableName, providerName, TableType.Table);
					if (CodeService.ShouldGenerate(fkTbl))
					{
						string fkClass = fk.ClassName;
						string fkClassQualified = provider.GeneratedNamespace + "." + fkClass;
						string fkMethod = fk.ClassName;
						string fkID = tbl.GetColumn(fk.ColumnName).PropertyName;
						string fkColumnID = fk.ColumnName;

						//it's possible this table is "relatin to itself"
						//check to make sure the class names are not the same
						//if they are, use the fk columnName
						if (fk.ClassName == className)
						{
							fkMethod = "Parent" + fk.ClassName;
						}

						if (usedPropertyNames.Contains(fk.ClassName))
						{
							fkMethod += "To" + fkID;
						}

						if (tbl.GetColumn(fkMethod) != null)
						{
							fkMethod += "Record";
						}
%>
		/// <summary>
		/// Returns a <%=fkClass%> ActiveRecord object related to this <%=className%>
		/// 
		/// </summary>
		public <%=fkClassQualified%> <%=fkMethod%>
		{
			get { return <%=fkClassQualified%>.FetchByID(this.<%=fkID%>); }
			set { SetColumnValue("<%=fkColumnID%>", value.<%=fkTbl.PrimaryKey.PropertyName%>); }
		}
		
		<%
			usedPropertyNames.Add(fk.ClassName);
		}
	}
}
		%>
		#endregion
		<%} else {%>
		//no foreign key tables defined (<%=tbl.ForeignKeys.Count.ToString() %>)
		<%} %>
		
		<%if (tbl.ManyToManys.Count > 0) { %>
		#region Many To Many Helpers
		<%
			TableSchema.ManyToManyRelationshipCollection mm = tbl.ManyToManys;
			if (mm != null)
			{
				ArrayList usedConstraints = new ArrayList();
				foreach (TableSchema.ManyToManyRelationship m in mm)
				{
					TableSchema.Table fkSchema = DataService.GetSchema(m.ForeignTableName, providerName, TableType.Table);
					if (fkSchema != null && !usedConstraints.Contains(fkSchema.ClassName) && CodeService.ShouldGenerate(fkSchema) && CodeService.ShouldGenerate(m.MapTableName, m.Provider.Name))
					{
						usedConstraints.Add(fkSchema.ClassName);
						string fkClass = fkSchema.ClassName;
						string fkClassQualified = provider.GeneratedNamespace + "." + fkClass;
				
		%>
		 
		public <%=fkClassQualified%>Collection Get<%=fkClass%>Collection() { return <%=className%>.Get<%=fkClass%>Collection(this.<%=thisPK%>); }
		public static <%=fkClassQualified%>Collection Get<%=fkClass%>Collection(<%= varPKType%> <%= varPK%>)
		{
			SubSonic.QueryCommand cmd = new SubSonic.QueryCommand(
				"SELECT * FROM <%=m.ForeignTableName%> INNER JOIN <%=m.MapTableName%> ON "+
				"<%=m.ForeignTableName%>.<%=m.ForeignPrimaryKey%>=<%=m.MapTableName%>.<%=m.MapTableForeignTableKeyColumn%> WHERE <%=m.MapTableName%>.<%=m.MapTableLocalTableKeyColumn%>=@<%=m.MapTableLocalTableKeyColumn%>", <%=className%>.Schema.Provider.Name);
			
			cmd.AddParameter("@<%=m.MapTableLocalTableKeyColumn%>", <%= varPK%>, DbType.<%= DataService.GetSchema(m.MapTableName, providerName).GetColumn(m.MapTableLocalTableKeyColumn).DataType.ToString() %>);
			IDataReader rdr = SubSonic.DataService.GetReader(cmd);
			<%=fkClass%>Collection coll = new <%=fkClass%>Collection();
			coll.LoadAndCloseReader(rdr);
			return coll;
		}
		
		public static void Save<%=fkClass%>Map(<%= varPKType%> <%= varPK%>, <%=fkClass%>Collection items)
		{
			QueryCommandCollection coll = new SubSonic.QueryCommandCollection();

			//delete out the existing
			QueryCommand cmdDel = new QueryCommand("DELETE FROM <%=m.MapTableName%> WHERE <%=m.MapTableLocalTableKeyColumn%>=@<%=m.MapTableLocalTableKeyColumn%>", <%=className%>.Schema.Provider.Name);
			cmdDel.AddParameter("@<%=m.MapTableLocalTableKeyColumn%>", <%= varPK%>);
			coll.Add(cmdDel);
			DataService.ExecuteTransaction(coll);
			foreach (<%=fkClass%> item in items)
			{
				<%=m.ClassName%> var<%=m.ClassName%> = new <%= m.ClassName%>();
				var<%=m.ClassName%>.SetColumnValue("<%=m.MapTableLocalTableKeyColumn%>", <%= varPK%>);
				var<%=m.ClassName%>.SetColumnValue("<%=m.MapTableForeignTableKeyColumn%>", item.GetPrimaryKeyValue());
				var<%=m.ClassName%>.Save();
			}
		}

		public static void Save<%=fkClass%>Map(<%= varPKType%> <%= varPK%>, System.Web.UI.WebControls.ListItemCollection itemList) 
		{
			QueryCommandCollection coll = new SubSonic.QueryCommandCollection();

			//delete out the existing
			 QueryCommand cmdDel = new QueryCommand("DELETE FROM <%=m.MapTableName%> WHERE <%=m.MapTableLocalTableKeyColumn%>=@<%=m.MapTableLocalTableKeyColumn%>", <%=className%>.Schema.Provider.Name);
			cmdDel.AddParameter("@<%=m.MapTableLocalTableKeyColumn%>", <%= varPK%>);
			coll.Add(cmdDel);
			DataService.ExecuteTransaction(coll);

			foreach (System.Web.UI.WebControls.ListItem l in itemList) 
			{
				if (l.Selected) 
				{
					<%=m.ClassName%> var<%=m.ClassName%> = new <%= m.ClassName%>();
					var<%=m.ClassName%>.SetColumnValue("<%=m.MapTableLocalTableKeyColumn%>", <%= varPK%>);
					var<%=m.ClassName%>.SetColumnValue("<%=m.MapTableForeignTableKeyColumn%>", l.Value);
					var<%=m.ClassName%>.Save();
				}
			}
		}

		public static void Save<%=fkClass%>Map(<%= varPKType%> <%= varPK%> , <%= varPKType%>[] itemList) 
		{
			QueryCommandCollection coll = new SubSonic.QueryCommandCollection();

			//delete out the existing
			 QueryCommand cmdDel = new QueryCommand("DELETE FROM <%=m.MapTableName%> WHERE <%=m.MapTableLocalTableKeyColumn%>=@<%=m.MapTableLocalTableKeyColumn%>", <%=className%>.Schema.Provider.Name);
			cmdDel.AddParameter("@<%=m.MapTableLocalTableKeyColumn%>", <%= varPK%>);
			coll.Add(cmdDel);
			DataService.ExecuteTransaction(coll);

			foreach (<%= varPKType%> item in itemList) 
			{
				<%=m.ClassName%> var<%=m.ClassName%> = new <%= m.ClassName%>();
				var<%=m.ClassName%>.SetColumnValue("<%=m.MapTableLocalTableKeyColumn%>", <%= varPK%>);
				var<%=m.ClassName%>.SetColumnValue("<%=m.MapTableForeignTableKeyColumn%>", item);
				var<%=m.ClassName%>.Save();
			}
		}
		
		public static void Delete<%=fkClass%>Map(<%= varPKType%> <%= varPK%>) 
		{
			QueryCommand cmdDel = new QueryCommand("DELETE FROM <%=m.MapTableName%> WHERE <%=m.MapTableLocalTableKeyColumn%>=@<%=m.MapTableLocalTableKeyColumn%>", <%=className%>.Schema.Provider.Name);
			cmdDel.AddParameter("@<%=m.MapTableLocalTableKeyColumn%>", <%= varPK%>);
			DataService.ExecuteQuery(cmdDel);
		}

		<%
			}
		}
	}
		%>
		#endregion
		<%} else {%>
		//no ManyToMany tables defined (<%=tbl.ManyToManys.Count.ToString() %>)
		<%} %>

		#region ObjectDataSource support
		<%
			string insertArgs = string.Empty;
			string updateArgs = string.Empty;
			string seperator = ",";
			
			foreach (TableSchema.TableColumn col in cols)
			{
				string propName = col.ArgumentName;
				bool useNullType = useNullables ? col.IsNullable : false;
				string varType = Utility.GetVariableType(col.DataType, useNullType, lang);
				
				updateArgs += varType + " " + propName + seperator;
				if (!col.AutoIncrement)
				{
					insertArgs += varType + " " + propName + seperator;
				}
			}
			if (insertArgs.Length > 0)
				insertArgs = insertArgs.Remove(insertArgs.Length - seperator.Length, seperator.Length);
 			if (updateArgs.Length > 0)
				updateArgs = updateArgs.Remove(updateArgs.Length - seperator.Length, seperator.Length);
		%>
		
		/// <summary>
		/// Inserts a record, can be used with the Object Data Source
		/// </summary>
		public static void Insert(<%=insertArgs%>)
		{
			<%=className %> item = new <%=className %>();
			<% 
			foreach (TableSchema.TableColumn col in cols) {
				if (!col.AutoIncrement) { 
			%>
			item.<%=col.PropertyName%> = <%=col.ArgumentName%>;
			<%
				}
			  } 
			%>
		
			if (System.Web.HttpContext.Current != null)
				item.Save(System.Web.HttpContext.Current.User.Identity.Name);
			else
				item.Save(System.Threading.Thread.CurrentPrincipal.Identity.Name);
		}
		
		/// <summary>
		/// Updates a record, can be used with the Object Data Source
		/// </summary>
		public static void Update(<%=updateArgs%>)
		{
			<%=className %> item = new <%=className %>();
			<% 
			foreach (TableSchema.TableColumn col in cols) 
			{
				%>
				item.<%=col.PropertyName%> = <%=col.ArgumentName%>;
				<%
			} 
			%>
			item.IsNew = false;
			if (System.Web.HttpContext.Current != null)
				item.Save(System.Web.HttpContext.Current.User.Identity.Name);
			else
				item.Save(System.Threading.Thread.CurrentPrincipal.Identity.Name);
		}

		#endregion

		#region Columns Struct
		public struct Columns
		{
			<% foreach (TableSchema.TableColumn col in cols) {%> public static string <%=col.PropertyName%> = @"<%=col.ColumnName%>";
			<%}%>			
		}
		#endregion
	}
}
